<?php
require_once 'TVB/Message/MessageHelper.php';

class Unpublished{

	private static $USER;
	private static $TIME;
	private static $ITEM_OBJ;
	private static $PUBLISH_OBJ;

	private static $log_items;
	private static $publish_log_ids;

	private static $media_ids=array('image'=>array(),'video'=>array());
	private static $folders=array();
	private static $casts=array();

    public static $dataArray;
	/**
	 * send message to MQ
	 */
	public static function send($type, $id, $programme_id = 0, $audit_log_id=0)
	{
		$config = ConfigReaderFactory::getInstance()->getConfigReader(AC::CONFIG_MQ)->getConfig();

		$result = true;
		try
		{
			$consumerConfig = $config->xpath("/config/consumer[@name='Unpublished']");
			$broker  = (string) $consumerConfig[0]->broker;
			$queue   = (string) $consumerConfig[0]->queue;
			$result &= MessageHelper::sendMessage($broker,$queue,array(
				'type'		 => $type,
				'id'		   => $id,
				'audit_log_id' => $audit_log_id,
				'user'		 => CommonUtils::get_user(),
				'programme_id' => $programme_id,
			));
		}
		catch(Stomp_Exception $e)
		{
			try{
				Model::updateBySql('update audit_log set action=:action,remarks=:remarks where id=:id',array(':action'=>AC::LOG_OP_UNPUBLISH_FAILED,':remarks'=>'Send data to MQ failed!',':id'=>$audit_log_id));
			}catch(PDOException $dbexp){ 
				error_log(print_r($dbexp,1));
				mail(CommonUtils::getAdminMail(), "Unpublished($type, $id) failed[update #1 publish_log status failed]. at server:".trim(`hostname`) , print_r($dbexp,1));
			}
			error_log(print_r($e,1));
			mail(CommonUtils::getAdminMail(),"Unpublished($type, $id, $programme_id, $audit_log_id) : MQ Server Error, At ".trim(`hostname`) , print_r($e,1));
			$result = false;
		}
		return (boolean)$result;
	}
	/**
	 * read MQ data AND update #2 db
	 */
	public static function read($type,$id,$audit_log_id,$user=null, $programme_id = 0){
		self::$TIME = date('Y-m-d H:i:s');
		self::$USER = $user ? $user : CommonUtils::get_user();
		self::$ITEM_OBJ    = new item_type();
		self::$PUBLISH_OBJ = new publish_log();
		self::$log_items   = array();
		self::$folders     = array();
		self::$casts       = array();
		self::$media_ids   = array('image'=>array(),'video'=>array());
		self::$dataArray   = array();

		$result = false;
		
		$dbConn1 = Model::$dbo['w']->getDbHandle();
		$dbConn2 = CommonUtils::getDbConn(1,'preview');

		$dbConn1->beginTransaction();
		$dbConn2->beginTransaction();

		try
		{
			$result = self::_func_routing($type,$id,'unpublished'); # db #2

			################## unpublish images & unpublish casts Start
			self::$folders = array_unique(self::$folders);
			self::$casts   = array_unique(self::$casts);
			$all_image = CommonUtils::getItemsByFolders($dbConn2->getDbHandle(), self::$folders); 
			if($type != 'programme' ){
				foreach($all_image as $index => $i_id){
					$not_related = true;
					$folders_of_image = CommonUtils::getFoldersByItemId($dbConn2->getDbHandle(), $i_id);
					foreach($folders_of_image as $f_id){
						# for bug 7680,7681
						if(!in_array($f_id, self::$folders)){ # image的一个Folder不在本次删除的所有folder内
							$not_related = false;
						}else{                                # 在本次删除的folder之内，说明可以删除 folder_item
							CommonUtils::exec_sql(
								$dbConn2->getDbHandle(),
								'DELETE `folder_item-language` FROM `folder_item-language`,folder WHERE '.
								'`folder_item-language`.folder_id=folder.id AND folder.folder_item_type_id=? '.
								'AND `folder_item-language`.item_id=? and folder.id=?',
								array(AC::FOLDER_TYPE_IMAGE, $i_id, $f_id)
							);
							CommonUtils::exec_sql(
								$dbConn2->getDbHandle(),
								'DELETE folder_item FROM folder_item,folder WHERE '.
								'folder_item.folder_id=folder.id AND folder.folder_item_type_id=? '.
								'AND folder_item.item_id=? and folder.id=?',
								array(AC::FOLDER_TYPE_IMAGE, $i_id, $f_id)
							);
							self::setData('folder_image', array('folder_id' => $f_id, 'image_id' => $i_id));
						}
					}
					if($not_related){// 可以被删除
						$result &= self::_media_unpublished($i_id,'image');
					}else{
						unset($all_image[$index]); // 将有关系的 image 从 all_image 中移除
					}
				}
			}else{ # delete all image
				foreach($all_image as $i_id){
					$result &= self::_media_unpublished($i_id,'image');
				}
			}

			# for bug 7680,7681 => delete folder_item
			foreach($all_image as $i_id){ # 可以删除的全部 image,下面的 folder_item也可以被删除
				$rs = CommonUtils::exec_sql(
					$dbConn2->getDbHandle(),
					'SELECT fi.folder_id FROM folder f,folder_item fi '.
					'WHERE fi.folder_id=f.id AND f.folder_item_type_id=? AND fi.item_id=?',
					array(AC::FOLDER_TYPE_IMAGE, $i_id)
				);
				foreach($rs as $row){
					self::setData('folder_image', array('folder_id' => $row['folder_id'], 'image_id' => $i_id));
				}

				CommonUtils::exec_sql(
					$dbConn2->getDbHandle(),
					'DELETE `folder_item-language` FROM `folder_item-language`,folder WHERE '.
					'`folder_item-language`.folder_id=folder.id AND folder.folder_item_type_id=? '.
					'AND `folder_item-language`.item_id=?',
					array(AC::FOLDER_TYPE_IMAGE, $i_id)
				);
				CommonUtils::exec_sql(
					$dbConn2->getDbHandle(),
					'DELETE folder_item FROM folder_item,folder WHERE '.
					'folder_item.folder_id=folder.id AND folder.folder_item_type_id=? '.
					'AND folder_item.item_id=?',
					array(AC::FOLDER_TYPE_IMAGE, $i_id)
				);
			}

			# 清除所有空 Folder
			foreach(self::$folders as $f_id){
				# for bug 7680 => delete folder_item
				#foreach($all_image as $i_id){
				#	CommonUtils::exec_sql(
				#		$dbConn2->getDbHandle(),
				#		'DELETE folder_item 
				#		 FROM folder_item,folder WHERE 
				#		   folder_item.folder_id=folder.id AND folder.folder_item_type_id=?
				#		 AND folder_item.item_id=? and folder.id=?',
				#		array(AC::FOLDER_TYPE_IMAGE, $i_id, $f_id)
				#	);
				#	self::setData('folder_image', array('folder_id' => $f_id, 'image_id' => $i_id));
				#}

				$has = CommonUtils::exec_sql(
					$dbConn2->getDbHandle(),
					'SELECT item_id FROM folder_item WHERE folder_id=?',
					array($f_id)
				);
				if(!$has) self::setData('folder',array('id'=>$f_id));
			}

			# unpublish cast
			foreach(self::$casts as $c_id){
				self::$log_items['cast'][$c_id] = true;
				self::setData('cast', array('id' => $c_id));
				$result &= CommonUtils::exec_sql($dbConn2->getDbHandle(), 'UPDATE cast SET status=? WHERE id=?',array(AC::STATUS_DELETED,$c_id));
			}
			############## End

			try 
			{
				$result &= self::_log();
			}
			catch(PDOException $e)
			{
				mail(CommonUtils::getAdminMail(), "Unpublished($type, $id) failed[update #1 db failed]. at server:".trim(`hostname`) , print_r($e,1));
			}
		}
		catch(PDOException $e)
		{
			mail(CommonUtils::getAdminMail(), "Unpublished($type, $id) failed[update #2 db failed]. at server:".trim(`hostname`) , print_r($e,1));
		}

		try
		{
			if($result)
			{
				if($audit_log_id)
				{
					Model::updateBySql('update audit_log set action=:action where id=:id',array(':action'=>AC::LOG_OP_UNPUBLISHING,':id'=>$audit_log_id));
				}

				# send message to portal 
				$items = self::$dataArray;
				self::uniqueData($items);
				$callback_data['operation_user']  = self::$USER;
				$callback_data['audit_log_id']    = $audit_log_id;
				$callback_data['unpublish_id']    = $id;
				$callback_data['unpublish_type']  = $type;
				$callback_data['publish_log_ids'] = self::$publish_log_ids;
				$callback_data['unpublish_items'] = $items;
				$callback_data['db3'] = array('delete'=>array());
				$gatter = new Processor();
				$delete = & $callback_data['db3']['delete'];
				switch(strtolower($type)){
					case 'programme': $delete[] = array('type'=>'Programme', 'keys'=>array('id'=>$id));  break;
					case 'episode':   $delete[] = array('type'=>'Episode',   'keys'=>array('id'=>$id));  break;
					case 'cast':      $delete[] = array('type'=>'Personage', 'keys'=>array('id'=>$id));  break;
					case 'video':     $delete[] = array('type'=>'Video',     'keys'=>array('id'=>$id));  break;
					case 'image':     $delete[] = array('type'=>'Image',     'keys'=>array('id'=>$id));  break;
					default:# infos
						$info_type = 'INFO_TYPE_'.strtoupper(substr($type,5));
						$info_type = constant("Processor::$info_type");
						$delete[]  = array('type'=>'Info','keys'=>array('info_id'=>$id,'info_type_id'=>$info_type));
				}
				if(in_array(strtolower($type),array('episode','cast'))){
					foreach(self::$media_ids as $media_type=>$media_data){
						foreach($media_data as $media_id){
							$delete[] = array('type'=>ucfirst($media_type), 'keys'=>array('id'=>$media_id));
						}
					}
					foreach(self::$casts as $cast_id){
						$delete[] = array('type'=>'Personage', 'keys'=>array('id'=>$cast_id)); 
					}
				}

				# for bug 7680,7681
				$_i = isset(self::$dataArray['folder_image']) ? self::$dataArray['folder_image'] : array();
				$_v = isset(self::$dataArray['folder_video']) ? self::$dataArray['folder_video'] : array();
				foreach(array('image_id'=>$_i,'video_id'=>$_v) as $t=>$r){
					$keys = array('item_type' => ($t=='image_id' ? AC::FOLDER_TYPE_IMAGE : AC::FOLDER_TYPE_VIDEO));
					foreach($r as $d){
						$keys['folder_id'] = $d['folder_id'];
						$keys['item_id']   = $d[$t];
						$delete[] = array('type'=>'FolderItem','keys'=>$keys);
					}
				};

				$message['callback_data'] = base64_encode(bzcompress(json_encode($callback_data),9));
				$message['vi_ids']        = $message['ii_ids'] = array();
				$message['programme_id']  = $programme_id;
				$message['action']        = 'unpublish'; 

				file_put_contents('/tmp/portal_unpublish.txt', print_r($items, 1));

				try{
					$result &= CommonUtils::sendDataToIiViProcess($message);
					$result &= self::_sendToSdes($type,$id);
				}catch(Stomp_Exception $e){
					throw new Exception("Send {$type} data to sdes failed($type, $id) : MQ Server Error, At ".trim(`hostname`).$e->getMessage());
				}
				if(!$result) throw new Exception("Can't send data to MQ.");

				$dbConn1->commit();
				$dbConn2->commit();
			}
			else
			{
				$dbConn1->rollBack();
				$dbConn2->rollBack();

				if($audit_log_id)
				{
					$result &= Model::updateBySql('update audit_log set action=:action,remarks=:remarks where id=:id',array(':action'=>AC::LOG_OP_UNPUBLISH_FAILED,':remarks'=>'Update #2 DB failed!',':id'=>$audit_log_id));
				}
			}
		}
		catch(Exception $e)
		{ 
			if($result){
				$dbConn1->rollBack();
				$dbConn2->rollBack();
			}
			mail(CommonUtils::getAdminMail(), "Unpublished($type, $id) failed[update #1 publish_log status failed]. at server:".trim(`hostname`) , print_r($e,1));
		}

		return (bool)$result;
	}

	private static function _sendToSdes($type,$id){
		if(in_array($type,array('programme','episode'))){
			$data = array();
			if($type=='programme'){
				$rs = Model::selectBySql("select distinct cpl_id from programme_cpl where cpl_company_code='TVB' and programme_id=$id");
				if($rs){
					foreach($rs as $row){
						$data['programme'][] = $row['cpl_id'];
					}
				}
			}else{
				$rs = Model::selectBySql("select distinct pl.cpl_id,e.onair_episode_no from episode e inner join programme_cpl pl on e.programme_id=pl.programme_id where e.id=$id");
				if($rs){
					foreach($rs as $row){
						$data['episode'][] = array('programme_no'=>$row['cpl_id'],'onair_episode_no'=>$row['onair_episode_no']);
					}
				}
			}
			if($data){
				$config = ConfigReaderFactory::getInstance()->getConfigReader(AC::CONFIG_MQ)->getConfig();
				$consumerConfig = $config->xpath("/config/consumer[@name='UnpublishedSDES']");
				$broker  = (string) $consumerConfig[0]->broker;
				$queue   = (string) $consumerConfig[0]->queue;
				MessageHelper::sendMessage($broker,$queue,$data);
			}
		}
		return true;
	}


	/**
	 * functions routing
	 */
	private static function _func_routing($type,$id,$suffix){
		$type   = strtolower($type);
		$prefix = substr($type,0,5);
		$param  = array($id,$type);

		switch($prefix)
		{
			case 'image':
			case 'video':
				$func_name = '_media_'.$suffix;
				$param[1] = $prefix;
			break;

			case 'info_':
				$func_name = '_info_'.$suffix;
			break;

			case 'cast':
				$func_name = 'pushCastFolders';
			break;

			default:
				$func_name = '_'.$type.'_'.$suffix;
			break;
		}
		#echo " call Function $func_name \n";
		return call_user_func_array("Unpublished::$func_name",$param);
	}


	############################# Unpublished Logs #################################
	private static function _log(){
		file_put_contents('/tmp/unpublish_data.txt',print_r(self::$log_items,1));
		foreach(self::$log_items as $type=>$values){
			foreach(array_keys($values) as $id){
				#echo " Insert publish_log record type:$type id:$id \n";
				$publish_log_id = self::$PUBLISH_OBJ->saveLog(
					AC::LOG_OP_UNPUBLISHING,
					$type,
					$id,
					self::$TIME,
					self::$USER,
					self::$ITEM_OBJ
				);
				self::$publish_log_ids[$type][] = $publish_log_id;
			}
		}
		return true;
	}

	############################# Send Data To MQ #################################
	/**
	 * infos unpublished
	 */
	private static function _info_unpublished($id,$type){
		$dbo	= CommonUtils::getDbConn(1,'preview')->getDbHandle();

		$sql	= "UPDATE $type SET status=:status WHERE id=:id";
		
		$param  = array(':status'=>AC::STATUS_DELETED,':id'=>$id);

		$result = CommonUtils::exec_sql($dbo,$sql,$param);

		self::$log_items[$type][$id] = true;

        $info_type_id = AC::$info_type_id[$type];
        self::setData('info', array('info_type_id' => $info_type_id, 'info_id' => $id));

		return $result;
	}

	/**
	 * media(image|video) unpublished
	 */
	private static function _media_unpublished($id,$type){
		$result = true;

		$dbo	= CommonUtils::getDbConn(1,'preview')->getDbHandle();

		$set_media_status_sql = "UPDATE $type SET status=:status WHERE id=:id";
		
		$result = CommonUtils::exec_sql($dbo, $set_media_status_sql, array(':status'=>AC::STATUS_DELETED,':id'=>$id));

		$folder_item_type_id = AC::FOLDER_TYPE_IMAGE;
		if('video'==$type)
		{
            $chapter_id = array();
			$folder_item_type_id = AC::FOLDER_TYPE_VIDEO;
			
			// delete episode-video table record
			$result &= CommonUtils::exec_sql($dbo, 'DELETE FROM `episode-video` WHERE video_id=:id',array(':id'=>$id));

			// SET chapter table status
			$sql = 'UPDATE chapter SET status=:status WHERE video_id=:id';
			$result &= CommonUtils::exec_sql($dbo, $sql, array(':status'=>AC::STATUS_DELETED,':id'=>$id));
											 
			$sql = "SELECT `id` FROM `chapter` WHERE `video_id`=:video_id";
			$rs = CommonUtils::exec_sql($dbo, $sql, array(':video_id' => $id));
			foreach ($rs as $row) {
                $chapter_id[] = $row['id'];
				self::$log_items['chapter'][$row['id']] = true;
                self::setData('chapter', array('id' => $row['id']));
			}

            #chapter-tvbcom_category
            if (!empty($chapter_id)) {
                $result &= self::unpublishChapterTvbcomCategory(implode(',', $chapter_id), $dbo);
            }
		}

		// delete folder item and language record
        $item_folders = 'SELECT id FROM folder WHERE folder_item_type_id=:type';

        $sql = "SELECT * FROM `folder_item` WHERE item_id=:id AND folder_id IN($item_folders)";
        $ret = CommonUtils::exec_sql($dbo, $sql, array(':type'=>$folder_item_type_id,':id'=>$id));
        foreach ($ret as $row) {
            if ($type == 'video') {
                self::setData('folder_video', array('folder_id' => $row['folder_id'], 'video_id' => $row['item_id']));
            } else {
                self::setData('folder_image', array('folder_id' => $row['folder_id'], 'image_id' => $row['item_id']));
            }
        }

		$result &= CommonUtils::exec_sql($dbo,"DELETE FROM `folder_item-language` WHERE item_id=:id AND folder_id IN($item_folders)",array(':type'=>$folder_item_type_id,':id'=>$id));
		$result &= CommonUtils::exec_sql($dbo,"DELETE FROM `folder_item` WHERE item_id=:id AND folder_id IN($item_folders)",array(':type'=>$folder_item_type_id,':id'=>$id));

		self::$log_items[$type][$id] = true;
        self::setData($type, array('id' => $id));
		self::$media_ids[$type][] = $id;

		return $result;
	}

    private function unpublishChapterTvbcomCategory($chapter_id, $dbo)
    {
        $sql = "DELETE FROM `chapter-tvbcom_category` WHERE `chapter_id` IN (" . $chapter_id . ")";
        $rs = CommonUtils::exec_sql($dbo, $sql);

        return $rs;
    }

	/**
	 * programme unpublished
	 */
	private static function _programme_unpublished($id){
		$result = true;

		$dbo	= CommonUtils::getDbConn(1,'preview')->getDbHandle();

		// programme update
		$result &= CommonUtils::exec_sql($dbo, 'UPDATE programme SET status=:status WHERE id=:id',array(':status'=>AC::STATUS_DELETED,':id'=>$id));

		// programme_cpl delete
		$result &= CommonUtils::exec_sql($dbo, 'DELETE FROM programme_cpl WHERE programme_id=:id',array(':id'=>$id));

		// programme-tvbcom_category delete
		$result &= CommonUtils::exec_sql($dbo, 'DELETE FROM `programme-tvbcom_category` WHERE programme_id=:id',array(':id'=>$id));

		// get all episodes, AND each episode update 
		$episodes= CommonUtils::exec_sql($dbo, 'SELECT id FROM episode WHERE programme_id=:id',array(':id'=>$id));
		foreach($episodes as $episode)
		{
			$result &= self::_episode_unpublished($episode['id']);
		}

		# append programme folder to self::$folders
		$programme_info = CommonUtils::exec_sql($dbo,'SELECT folders,casts FROM programme WHERE id=?',array($id));
		self::$folders  = array_merge(self::$folders,explode(',',$programme_info[0]['folders']));
		$programme_casts = CommonUtils::getCastIdsByCastJson($programme_info[0]['casts']);
		foreach($programme_casts as $c_id){
			self::$casts[] = $c_id;
			self::pushCastFolders($c_id);
		}
		// get all video
		$all_video = CommonUtils::getItemsByFolders($dbo,$programme_info[0]['folders'],false,true);
		foreach($all_video as $v_id)
		{
			$result &= self::_media_unpublished($v_id,'video');
		}

		self::$log_items['programme'][$id] = true;
        self::setData('programme', array('id' => $id));

		return $result;
	}

	/**
	 * episode unpublished
	 */
	private static function _episode_unpublished($id){
		$result = true;

		$dbo	= CommonUtils::getDbConn(1,'preview')->getDbHandle();

		// UPDATE episode record
		$result &= CommonUtils::exec_sql($dbo, 'UPDATE episode SET status=:status WHERE id=:id',array(':status'=>AC::STATUS_DELETED,':id'=>$id));
		// DELETE episode-video table record
		//$result &= CommonUtils::exec_sql($dbo, 'DELETE FROM `episode-video` WHERE episode_id=:id',array(':id'=>$id));
		
		// get all infos, AND each info update
		$get_all_infos_sql = '
			SELECT id, "info_address"			 AS type FROM info_address			 WHERE episode_id = :id UNION ALL
			SELECT id, "info_award"			   AS type FROM info_award			   WHERE episode_id = :id UNION ALL
			SELECT id, "info_biography"		   AS type FROM info_biography		   WHERE episode_id = :id UNION ALL
			SELECT id, "info_general_information" AS type FROM info_general_information WHERE episode_id = :id UNION ALL
			SELECT id, "info_pageant" 			  AS type FROM info_pageant				WHERE episode_id = :id UNION ALL
			SELECT id, "info_product"			 AS type FROM info_product			 WHERE episode_id = :id UNION ALL
			SELECT id, "info_q_a"				 AS type FROM info_q_a				 WHERE episode_id = :id UNION ALL
			SELECT id, "info_recipe"			  AS type FROM info_recipe			  WHERE episode_id = :id UNION ALL
			SELECT id, "info_song"				AS type FROM info_song				WHERE episode_id = :id 	
		';
		$infos  = CommonUtils::exec_sql($dbo, $get_all_infos_sql,array(':id'=>$id));
		foreach($infos as $info){
			$result &= self::_info_unpublished($info['id'],$info['type']);
		}
		# bug 7499
		#CommonUtils::exec_sql($dbo,'DELETE FROM `episode-video` WHERE episode_id=?',array($id));

		# append episode folder to self::$folders
		$episode_info  = CommonUtils::exec_sql($dbo,'SELECT programme_id,folders,casts FROM episode WHERE id=?',array($id));
		self::$folders = array_merge(self::$folders,explode(',',$episode_info[0]['folders']));
		# append episode casts to self::$casts
		$programme_info  = CommonUtils::exec_sql($dbo, 'SELECT casts FROM programme WHERE id=?',array($episode_info[0]['programme_id']));
		$episode_casts   = CommonUtils::getCastIdsByCastJson($episode_info[0]['casts']);
		$programme_casts = CommonUtils::getCastIdsByCastJson($programme_info[0]['casts']);
		foreach($episode_casts as $c_id){
			if(!in_array($c_id, $programme_casts)){
				self::$casts[]  = $c_id;
				self::pushCastFolders($c_id);
			}
		}

		self::$log_items['episode'][$id] = true;
        self::setData('episode', array('id' => $id));

		return $result;
	}

	/**
	 * add cast folder ids to self::$folders
	 */
	private static function pushCastFolders($id){
		$dbo	= CommonUtils::getDbConn(1,'preview')->getDbHandle();
		
		# append episode folder to self::$folders
		$cast_info  = CommonUtils::exec_sql($dbo,'SELECT folders FROM cast WHERE id=?',array($id));
		self::$folders = array_merge(self::$folders,explode(',',$cast_info[0]['folders']));
		self::$casts[]  = $id;
		return true;
	}

    private static function setData($type, array $record=array())
    {
        self::$dataArray[$type][] = $record;
    }

    public static function uniqueData(&$dataArray)
    {
        $unique = array();
        foreach ($dataArray as $type=>$data) {
            if (empty($data)) {
                continue;
            }

            foreach ($data as $key=>$row) {
                switch ($type) {
                case 'folder_image':
                    $id = $row['folder_id'] . '_' . $row['image_id'];
                    break;
                case 'folder_video':
                    $id = $row['folder_id'] . '_' .$row['video_id'];
                    break;
                case 'info':
                    $id = $row['info_id'] . '_' . $row['info_type_id'];
                    break;
                default:
                    $id = $row['id'];
                    break;
                }
                if (!isset($unique[$type]) || !in_array($id, $unique[$type])) {
                    $unique[$type][] = $id;
                } elseif(in_array($id, $unique[$type])) {
                    unset($dataArray[$type][$key]);
                } 
            }
        }
    }
}
